// (C) 2021 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

`define GENERAL_MAX_ADDR     3 // define how many DW registers are used
//Define Address for each regiter
`define ADC_TARGET_ADDR      16'h0
`define REMOTE_JUMPER_ADDR   16'h4
`define IIC_MM_STATUS_ADDR   16'h8


//Define Default Value
`define ADC_BASE_ADDR_DEF            16'h4200
`define ADC_RANGE_DEF                16'h0100
`define REMOTE_JUMPER_BASE_ADDR_DEF  16'hC100
`define REMOTE_JUMPER_RANGE_DEF      16'h0100


module general_csr 
(
    input clk,
    input reset,

    //avmm interface
    input      [31:0] avmm_address,
    input             avmm_write,
    input      [31:0] avmm_writedata,          
    input             avmm_read,     
    output reg [31:0] avmm_readdata,      
    output reg        avmm_readdatavalid, 
    output            avmm_waitrequest,           
    input      [ 3:0] avmm_byteenable,
	 
	 //error report
	 output            invalid_access,
	 input      [ 3:0] status_reg
);

wire [15:0] addr_local; //Only 16 bits out of 32 bits avmm_address supported
reg  [31:0] general_reg [`GENERAL_MAX_ADDR-1:0]; //local register
reg  [31:0] illegal_write;

reg         invalid_read;
reg         invalid_write;


assign avmm_waitrequest = 1'b0;

assign addr_local       = avmm_address[15:0];

assign invalid_access   =  invalid_write || invalid_read;


//invalid_read, using combinational logic to report error
always @ ( * ) begin
    if ( reset ) begin
		  invalid_read       = 1'b0;
    end else begin
        if ( avmm_read && !( |avmm_address[31:16]) && (&avmm_byteenable) ) begin
            case (addr_local)
                `ADC_TARGET_ADDR      : begin
						 invalid_read           =   1'b0;
                 end
                `REMOTE_JUMPER_ADDR   : begin
						 invalid_read           =   1'b0;
                 end
					 `IIC_MM_STATUS_ADDR   : begin
						 invalid_read           =   1'b0;
					  end
                 default              : begin
						 invalid_read           =   1'b1;
                 end
            endcase
        end
		  else begin
			  invalid_read                   =   1'b0;
		  end
    end
end

//read registers
always @ ( posedge clk ) begin
    if ( reset ) begin
        avmm_readdata     <= 32'h0;
    end else begin
        if ( avmm_read && !( |avmm_address[31:16]) && (&avmm_byteenable) ) begin
            case (addr_local)
                `ADC_TARGET_ADDR      : begin
					    avmm_readdata         <=   {`ADC_RANGE_DEF, `ADC_BASE_ADDR_DEF};
                 end
                `REMOTE_JUMPER_ADDR   : begin
					    avmm_readdata         <=   {`REMOTE_JUMPER_RANGE_DEF, `REMOTE_JUMPER_BASE_ADDR_DEF};
                 end
					 `IIC_MM_STATUS_ADDR   : begin
					    avmm_readdata         <=   {28'b0, status_reg};
					  end
                 default              : begin
					    avmm_readdata         <=   32'hFFFF_FFFF; //reture bad addr
                 end
            endcase
        end
    end
end

//readvalid
always @ ( posedge clk ) begin
    if ( reset ) begin
        avmm_readdatavalid <= 1'b0;
    end else begin
        if ( avmm_read && (&avmm_byteenable) && (!invalid_read) ) begin
            avmm_readdatavalid <= 1'b1; //readvalid asserts one clock cycle after read assetted.
        end else begin
            avmm_readdatavalid <= 1'b0;
        end
    end
end

//No write access is allowed
always @ ( * ) begin
   if (reset) begin
	   invalid_write      = 1'b0;
	end
	else begin
	   if(avmm_write) begin
		   invalid_write   = 1'b1;
		end
		else begin
		   invalid_write   = 1'b0;
		end
	end
end


endmodule    